package wsi.dataguide;

import java.util.Stack;
import java.util.logging.Logger;

import org.rygh.core.xml.AbstractXmlParser;
import org.rygh.core.xml.UXml;
import org.rygh.core.xml.XmlPath;
import org.rygh.semantic.gui.swing.input.Input;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import wsi.dataguide.tree.WSXmlLeaf;
import wsi.dataguide.tree.WSXmlObject;

public class DataGuideLoader extends AbstractXmlParser {
	private final Logger log = Logger.getLogger(getClass().getName());

	private final DataGuide dataGuide = new DataGuide();
	private final Stack<WSXmlLeaf> stack = new Stack<>();
	private final String xml;

	private Input currentKey = null;
	private boolean isInElement = false;

	public DataGuideLoader(String xml) {
		this.xml = xml;
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		WSXmlLeaf leaf = stack.peek();

		if (qName.equals(WSXmlObject.PREFIX + ":element")) {
			assert isInElement;
			assert currentKey != null;

			leaf.getValue().addValue(currentKey, getString());
			clearStringBuffer();

			isInElement = false;
		} else if (qName.equals(WSXmlObject.PREFIX + ":item")) {
			assert !isInElement;
			assert currentKey != null;

			currentKey = null;
		} else {
			if (!qName.equals(dataGuide.getRoot().getValue().getName())) {
				assert (leaf.getValue().getName().equals(qName));
				stack.pop();
			}
		}
	}

	public DataGuide load() {
		stack.push(dataGuide.getRoot());

		UXml.parse(this, xml);

		return dataGuide;
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		WSXmlLeaf parent = stack.peek();
		String prefix = "";

		if (qName.startsWith(WSXmlObject.PREFIX)) {
			if (qName.equals(WSXmlObject.PREFIX + ":item")) {
				currentKey = new Input(attributes.getValue(0));
			} else if (qName.equals(WSXmlObject.PREFIX + ":element")) {
				isInElement = true;
			} else {
				log.info("unknown qName " + qName);
			}
		} else {
			if (!qName.equals(dataGuide.getRoot().getValue().getName())) {
				WSXmlObject node = new WSXmlObject(qName);
				boolean isAttr = false;

				for (int i = 0; i < attributes.getLength(); i++) {
					String name, value;

					name = attributes.getQName(i);
					value = attributes.getValue(i);

					node.addAttribute(name, value);

					if (name.endsWith("isAttribute"))
						isAttr = Boolean.parseBoolean(value);
				}

				WSXmlLeaf leaf = new WSXmlLeaf(parent, node);

				if (parent.getValue() != null && parent.getXpath() != null) {
					if (isAttr)
						prefix = String.format("%s/@%s", parent.getXpath(),
								qName);
					else
						prefix = String.format("%s/%s[%d]", parent.getXpath(),
								qName, parent.getIndex(leaf));
				} else
					prefix = String.format("/%s", qName);

				leaf.setXpath(new XmlPath(prefix));
				stack.push(leaf);
			}
		}

		clearStringBuffer();
	}

	@Override
	public void startPrefixMapping(String prefix, String uri)
			throws SAXException {
		dataGuide.addPrefix(prefix, uri);
	}
}
